/**
 * @method Verification 输入框验证解决方案
 * @author Lkx
 * @for Kxui
 * @for method
 *
 * @method use 开始使用
 */

(function (factory) {

  if ((typeof exports === 'object') && (typeof module !== 'undefined')) {
    module.exports = factory();
  } else {
    window.Kxui.verification = factory();
  }

}(function () {

  'use strict';

  let Kxui = window.Kxui;
  let ruleText = {
    'empty': '请输入内容',
    'num': '请输入数字 (不允许存在小数)',
    'letter': '请输入英文字母',
    'decimal': '请输入数字 (允许存在小数)',
    'phone': '请输入手机号码',
    'chinese': '请输入中文汉字',
    'color': '请输入十六进制颜色',
    'id': '请输入身份证号码',
    'url': '请输入 URL 地址',
    'email': '请输入邮箱号码',
    'IPv4': '请输入 IPv4 地址'
  };

  /**
   * 逻辑层
   * @method Logic
   * @for Drop
   * @param {object} parameter 配置参数
   */
  let Logic = function (parameter) {
    this.parameter = (typeof parameter === 'object') ? parameter : {};
    this.init();
  };

  Logic.prototype = {

    /**
     * 初始化
     * @method init
     * @for Logic
     */
    init: function () {
      this.el = Kxui.method.getDom(this.parameter.el);
      if (!this.parameter.el) {
        throws(0, 0);
      } else if (!this.el) {
        throws(1, 1, this.parameter.el);
      } else {
        let input = Kxui.method.sonQueDom(this.el, 'input');
        let textarea = Kxui.method.sonQueDom(this.el, 'textarea');
        this.elChildren = input.concat(textarea);
        if (!this.elChildren || this.elChildren.length <= 0) {
          throws(1, 2, this.parameter.el);
        } else {
          this.variable();
        }
      }
    },

    /**
     * 变量生成
     * @method variable
     * @for init
     */
    variable: function () {
      this.aniScrollSwitch = false;
      this.diy = (typeof this.parameter.diy === 'object' ? this.parameter.diy : false);

      this.danger = (typeof this.parameter.danger === 'object' ? this.parameter.danger : false);
      this.dangerTips = (typeof this.danger.tips === 'boolean' ? this.danger.tips : false);
      this.dangerTipsO = '';

      this.callback = (typeof this.parameter.callback === 'function' ? this.parameter.callback : function () {});
      this.callbackValue = '';

      this.success = (typeof this.parameter.success === 'object' ? this.parameter.success : false);
      this.successShow = (typeof this.success.show === 'boolean' ? this.success.show : true);

      if (this.parameter.aniScroll) {
        this.aniScroll = Kxui.method.getDom(this.parameter.aniScroll);
        if (this.aniScroll) {
          this.aniScrollSwitch = true;
        } else {
          throws(1, this.parameter.aniScroll, true);
        }
      }
      this.rule();
    },

    /**
     * 获取验证规则组
     * @method rule
     * @for variable
     */
    rule: function () {
      for (let i = 0; i < this.elChildren.length; i++) {
        let dom = this.elChildren[i];
        let verification = Kxui.method.atrDom(dom, 'kxui-verification');
        if (verification && typeof verification === 'string') {
          let Verification = Kxui.method.delSpace(verification).split(',');
          this.action(dom, dom.value, Verification);
          if (i === this.elChildren.length - 1) {
            this.throwCallback();
          }
        }
      }
    },

    /**
     * 执行验证动作
     * @method action
     * @for rule
     * @param {object} input 当前操作的输入框
     * @param {string} value 需要验证的内容
     * @param {string} rule 需要验证的规则
     */
    action: function (input, value, rule) {
      let that = this;
      let index = 'kxui-' + Kxui.method.random(16);
      let ruleCommon = that.ruleCommon(input, value, rule);
      if (ruleCommon === 'success') {
        success();
      } else {
        error(ruleCommon);
      }

      /**
       * 成功公共动作
       * @method success
       * @for action
       */
      function success() {
        if (that.successShow) {
          Kxui.method.addClass(input, 'kxui-verification kxui-verification-success ');

          if (that.success.color) {
            that.successStyle();
          }
        }
        if (!Kxui.method.atrDom(input, 'kxui-verification-on')) {
          Kxui.method.atrDom(input, 'kxui-verification-on', true);
          that.event(input, rule, index);
        }
      }

      /**
       * 错误公共动作
       * @method error
       * @for action
       */
      function error(text) {
        Kxui.method.atrDom(input, 'kxui-verification-index', index);
        Kxui.method.addClass(input, 'kxui-verification kxui-verification-danger');

        if (that.aniScrollSwitch) {
          that.aniScrollSwitch = false;
          Kxui.method.aniScroll((input.offsetTop - 100), that.aniScroll);
        }

        if (!Kxui.method.atrDom(input, 'kxui-verification-on')) {
          Kxui.method.atrDom(input, 'kxui-verification-on', true);
          that.event(input, rule, index);

          if (kxui.popup && that.dangerTips) {

            kxui.popup.tips(text, input, {
              style: 'danger',
              diy: {
                background: that.danger.color
              }
            });

          } else {
            that.skeleton(input, rule, index, text);
          }
        }

        if (that.danger.color) {
          that.dangerStyle();
        }
      }
    },

    /**
     * 错误监听
     * @method event
     * @for action
     * @param {object} input 当前操作的输入框
     * @param {string} rule 需要验证的规则
     * @param {string} index 唯一标识
     */
    event: function (input, rule, index) {
      let that = this;

      // 监听输入框输入
      input.addEventListener('input', onInput);

      /**
       * 监听错误输入框输入
       * @method onInput
       * @for event
       */
      function onInput() {
        let value = input.value;
        let ruleCommon = that.ruleCommon(input, value, rule);
        if (ruleCommon === 'success') {
          success();
        } else {
          error(ruleCommon);
        }

        /**
         * 成功公共动作
         * @method success
         * @for event
         */
        function success() {
          Kxui.method.delClass(input, 'kxui-verification-danger');
          if (that.successShow) {
            Kxui.method.addClass(input, 'kxui-verification-success');

            if (that.success.color) {
              that.successStyle();
            }
          }

          if (that.dangerTips && that.dangerTipsO) {
            kxui.popup.close(that.dangerTipsO);
            that.dangerTipsO = '';
          } else if (Kxui.method.getDom('#' + index)) {
            input.parentNode.removeChild(Kxui.method.getDom('#' + index));
          }

          that.throwCallback();
        }

        /**
         * 错误公共动作
         * @method error
         * @for event
         */
        function error(text) {
          Kxui.method.delClass(input, 'kxui-verification-success');
          Kxui.method.addClass(input, 'kxui-verification-danger');

          if (kxui.popup && that.dangerTips) {

            if (that.dangerTipsO) {
              kxui.popup.close(that.dangerTipsO);
            }

            that.dangerTipsO = kxui.popup.tips(text, input, {
              style: 'danger',
              diy: {
                background: that.danger.color
              },
              timeCall: function () {
                that.dangerTipsO = '';
              }
            });

          } else {
            if (!Kxui.method.getDom('#' + index)) {
              that.skeleton(input, rule, index, text);
            } else if (text) {
              Kxui.method.getDom('#' + index).innerHTML = text;
            }
          }

          if (that.danger.color) {
            that.dangerStyle();
          }

          that.throwCallback();
        }
      }
    },

    /**
     * 创建错误骨架
     * @method skeleton
     * @for action/event
     * @param {object} input 当前操作的输入框
     * @param {string} rule 需要验证的规则
     * @param {string} index 唯一标识
     * @param {string} text 自定义错误文案
     */
    skeleton: function (input, rule, index, text) {
      let W = input.offsetWidth;
      let H = input.offsetHeight;
      let T = input.offsetTop;
      let L = input.offsetLeft;
      let DT = this.danger.top ? Number(this.danger.top) : 3;
      let DC = this.danger.color ? this.danger.color : '';
      let content = Kxui.method.addDom('<div id="' + index + '" class="kxui-verification-danger-text" style="width:' + W + 'px;top:' + (T + H + DT) + 'px;left:' + L + 'px;color:' + DC + '">' + (text ? text : ruleText[rule]) + '</div>');
      input.parentNode.appendChild(content);
    },

    /**
     * 自定义成功样式
     * @method successStyle
     * @for action/event
     */
    successStyle() {
      let head = Kxui.method.getDom('head');
      let successStyle = Kxui.method.getDom('#kxui-verification-success-style');
      if (!successStyle) {
        let style = Kxui.method.addDom('<style id="kxui-verification-success-style">' +
          '.kxui-verification-success{color:' + this.success.color + ' !important;border-color:' + this.success.color + ' !important}' +
          '.kxui-verification-success:hover,.kxui-verification-success:focus{border-color:' + this.success.color + ' !important}' +
          '</style>');
        head.appendChild(style);
      }
    },

    /**
     * 自定义错误样式
     * @method dangerStyle
     * @for action/event
     */
    dangerStyle() {
      let head = Kxui.method.getDom('head');
      let dangerStyle = Kxui.method.getDom('#kxui-verification-danger-style');
      if (!dangerStyle) {
        let style = Kxui.method.addDom('<style id="kxui-verification-danger-style">' +
          '.kxui-verification-danger{color:' + this.danger.color + ' !important;border-color:' + this.danger.color + ' !important}' +
          '.kxui-verification-danger:hover,.kxui-verification-danger:focus{border-color:' + this.danger.color + ' !important}' +
          '</style>');
        head.appendChild(style);
      }
    },

    /**
     * 规则共同
     * @method ruleDefault
     * @for action/event
     * @param {object} input 当前操作的输入框
     * @param {string} value 需要验证的内容
     * @param {string} rule 需要验证的规则
     * @return {object/string} 验证错误文案与成功状态
     */
    ruleCommon(input, value, rule) {
      let ruleLength = this.ruleLength(input, value);
      let ruleDiy = this.ruleDiy(value, rule);
      let ruleDefault = this.ruleDefault(value, rule);
      let fillable = Kxui.method.atrDom(input, 'kxui-verification-fillable');
      if ((fillable || fillable === '') && !value) {
        return 'success';
      } else if (ruleLength !== 'success') {
        return ruleLength;
      } else if (ruleDiy !== 'success') {
        return ruleDiy;
      } else if (ruleDefault !== 'success') {
        return ruleDefault;
      } else {
        return 'success';
      }
    },

    /**
     * 默认规则验证
     * @method ruleDefault
     * @for ruleCommon
     * @param {string} value 需要验证的内容
     * @param {string} rule 需要验证的规则
     * @return {boolean} 根据验证情况进行返回布尔值
     */
    ruleDefault: function (value, rule) {
      for (let i = 0; i < rule.length; i++) {
        let defaultRule = ruleText[rule[i]];
        if (defaultRule) {
          if (!value || !Kxui.method.formTest(value, rule[i])) {
            return defaultRule;
          }
        }
      }
      return 'success';
    },

    /**
     * 长度范围验证
     * @method ruleLength
     * @for ruleCommon
     * @param {object} input 当前操作的输入框
     * @param {string} value 需要验证的内容
     * @return {string} 通过状态或错误文案
     */
    ruleLength: function (input, value) {
      let min = Kxui.method.atrDom(input, 'kxui-verification-min');
      let max = Kxui.method.atrDom(input, 'kxui-verification-max');
      if (min && value.length < Number(min)) {
        return '输入内容不能少于 ' + min + ' ( 当前 ' + value.length + ' )';
      }

      if (max && value.length > Number(max)) {
        return '输入内容不能大于 ' + max + ' ( 当前 ' + value.length + ' )';
      }
      return 'success';
    },

    /**
     * 自定义规则验证
     * @method ruleDiy
     * @for ruleCommon
     * @param {string} value 需要验证的内容
     * @param {string} rule 需要验证的规则
     * @return {string} 通过状态或错误文案
     */
    ruleDiy: function (value, rule) {
      if (this.diy) {
        for (let i = 0; i < this.diy.length; i++) {
          let DIY = this.diy[i];
          for (let r = 0; r < rule.length; r++) {
            if (DIY.name === rule[r]) {
              let Rule = (DIY.rule === 'object' ? DIY.rule : new RegExp(DIY.rule));
              if (!Rule.test(value)) {
                return DIY.text;
              }
            }
          }
        }
      }
      return 'success';
    },

    /**
     * 验证结果回调
     * @method throwCallback
     * @for variable
     */
    throwCallback: function () {
      let cache = this.callbackValue;
      for (let i = 0; i < this.elChildren.length; i++) {
        let li = this.elChildren[i];
        if (Kxui.method.hasClass(li, 'kxui-verification-danger')) {
          this.callbackValue = false;
          break;
        } else if (i === this.elChildren.length - 1) {
          this.callbackValue = true;
        }
      }

      if (cache !== this.callbackValue) {
        this.callback(this.callbackValue);
      }
    }
  };

  /**
   * 控制台错误/警告
   * @method throws
   * @for variable
   * @param {number} error 抛出错误的类型 0:警告 1:错误
   * @param {number} num 输入警告文案编号
   * @param {string} dome 发生错误的节点
   */
  function throws(error, num, dome) {
    if (Kxui.configuration.debug) {
      let nums = {};
      nums[0] = '配置参数 {el} 不能为空';
      nums[1] = '无法找到 {' + dome + '} 节点或存在多个 {' + dome + '} 节点';
      nums[2] = '配置节点 {' + dome + '} 子节点必须存在 {input} 或 {textarea} 标签';
      let text = 'Kxui-' + Kxui.about.version + '： 模块 {verification} ' + nums[num] + '，请检查修改。';
      error === 1 ? console.error(text) : console.warn(text);
    }
  }

  /**
   * 输入框验证解决方案
   * @method Verification
   */
  let Verification = function () {
    this.name = 'Verification';
    this.info = 'Input box verification solution';
  };

  Verification.fn = Verification.prototype;

  /**
   * 开始使用
   * @method use
   * @for Verification
   * @param {object} parameter 配置参数
   */
  Verification.fn.use = function (parameter) {
    new Logic(parameter);
  };

  return new Verification();

}));